Developer Documentation

QuickTime 4 API Documentation

Inside Macintosh: Files

Previous | Chapter Top | Chapter Contents | Next |

Selecting a Directory

You can present the recommended user interface for selecting a directory by calling the CustomGetFile procedure and passing it the addresses of a custom file filter function and a dialog hook function. See "Selecting Volumes and Directories" for a description of the appearance and behavior of the directory selection dialog box.

The file filter function used to select directories is quite simple; it ensures that only directories, not files, are listed in the dialog box displayed by CustomGetFile . Listing 3-16 defines a file filter function you can use for this purpose.

Listing 16 A file filter function that lists only directories

FUNCTION MyCustomFileFilter (pb: CInfoPBPtr; myDataPtr: Ptr): Boolean;
CONST
    kFolderBit = 4;                             {bit set in ioFlAttrib for a directory}
BEGIN                                           {list directories only}
    MyCustomFileFilter := NOT BTst(pb^.ioFlAttrib, kFolderBit);
END;

The function MyCustomFileFilter simply inspects the appropriate bit in the file attributes ( ioFlAttrib ) field of the catalog information parameter block passed to it. If the directory bit is set, the file filter function returns FALSE , indicating that the item should appear in the list; otherwise, the file filter function returns TRUE to exclude the item from the list. Because a volume is identified via its root directory, volumes also appear in the list of items in the dialog box.

The title of the Select button should identify which directory is available for selection. You can use the SetButtonTitle procedure defined in Listing 3-17 to set the title of a button.

Your dialog hook function calls the SetButtonTitle procedure to copy the truncated title of the selected item into the Select button. This title eliminates possible user confusion about which directory is available for selection. If no item in the list is selected, the dialog hook function uses the name of the directory shown in the pop-up menu as the title of the Select button.

Listing 17 Setting a button's title

PROCEDURE SetButtonTitle (ButtonHdl: Handle; name: Str255; ButtonRect: Rect);
VAR
    result:     Integer;        {result of TruncString}
    width:      Integer;        {width available for name of directory}
BEGIN
    gPrevSelectedName := name;
    WITH ButtonRect DO
        width := (right - left) - (StringWidth('Select ""') + CharWidth(''));
    result := TruncString(width, name, smTruncMiddle);
    SetCTitle(ControlHandle(ButtonHdl), CONCAT('Select "', name, '"'));
    ValidRect(ButtonRect);
END;

The SetButtonTitle procedure is passed a handle to the button whose title is to be changed, the name of the directory available for selection, and the button's enclosing rectangle. The global variable gPrevSelectedName holds the full directory name, before truncation.

A dialog hook function manages most of the process of letting the user select a director. Listing 3-18 defines a dialog hook function that handles user selections in the dialog box.

Listing 18 Handling user selections in the directory selection dialog box

FUNCTION MyDlgHook (item: Integer; theDialog: DialogPtr; myDataPtr: Ptr):
                         Integer;
CONST
    kGetDirBTN          = 10;               {Select directory button}
TYPE
    SFRPtr              = ^StandardFileReply;
VAR
    myType:             Integer;            {menu item selected}
    myHandle:           Handle;             {needed for GetDItem}
    myRect:             Rect;               {needed for GetDItem}
    myName:             Str255;
    myPB:               CInfoPBRec;
    mySFRPtr:           SFRPtr;
    myErr:              OSErr;
BEGIN
    MyDlgHook := item;              {default, except in special cases below}
    IF GetWRefCon(WindowPtr(theDialog)) <> LongInt(sfMainDialogRefCon) THEN
        Exit(MyDlgHook);            {this function is only for main dialog box}

    GetDItem(theDialog, kGetDirBTN, myType, myHandle, myRect);
    IF item = sfHookFirstCall THEN
        BEGIN
            {Determine current folder name and set title of Select button.}
            WITH myPB DO
                BEGIN
                    ioCompletion := NIL;
                    ioNamePtr := @myName;
                    ioVRefNum := GetSFCurVol;
                    ioFDirIndex := - 1;
                    ioDirID := GetSFCurDir;
                END;
            myErr := PBGetCatInfo(@myPB, FALSE);
            SetButtonTitle(myHandle, myName, myRect);
        END
    ELSE
        BEGIN
            {Get mySFRPtr from 3rd parameter to hook function.}
            mySFRPtr := SFRPtr(myDataPtr);
            {Track name of folder that can be selected.}
            IF (mySFRPtr^.sfIsFolder) OR (mySFRPtr^.sfIsVolume) THEN
                myName := mySFRPtr^.sfFile.name
            ELSE
                BEGIN
                    WITH myPB DO
                        BEGIN
                            ioCompletion := NIL;
                            ioNamePtr := @myName;
                            ioVRefNum := mySFRPtr^.sfFile.vRefNum;
                            ioFDirIndex := -1;
                            ioDrDirID := mySFRPtr^.sfFile.parID;
                        END;
                    myErr := PBGetCatInfo(@myPB, FALSE);
                END;
            {Change directory name in button title as needed.}
            IF myName <> gPrevSelectedName THEN
                SetButtonTitle(myHandle, myName, myRect);

            CASE item OF
                kGetDirBTN:                             {force return by faking a cancel}
                    MyDlgHook := sfItemCancelButton;
                sfItemCancelButton:
                    gDirSelectionFlag := FALSE;         {flag no directory was selected}
                OTHERWISE
                    ;
            END; {CASE}
        END;
END;

The MyDlgHook dialog hook function defined in Listing 3-18 calls the File Manager function PBGetCatInfo to retrieve the name of the directory to be selected. When the dialog hook function is first called (that is, when item is set to sfHookFirstCall ), MyDlgHook determines the current volume and directory by calling the functions GetSFCurVol and GetSFCurDir . When MyDlgHook is called each subsequent time, MyDlgHook calls PBGetCatInfo with the volume reference number and directory ID of the previously opened directory.

When the user clicks the Select button, MyDlgHook returns the item sfItemCancelButton . When the user clicks the real Cancel button, MyDlgHook sets the global variable gDirSelectionFlag to FALSE , indicating that the user didn't select a directory. The function DoGetDirectory uses that variable to distinguish between clicks of Cancel and clicks of Select.

The function DoGetDirectory defined in Listing 3-19 uses the file filter function and the dialog hook functions defined above to manage the directory selection dialog box. On exit, DoGetDirectory returns a standard file reply record describing the selected directory.

Listing 19Presenting the directory selection dialog box

FUNCTION DoGetDirectory: StandardFileReply;
VAR
    myReply:                StandardFileReply;
    myTypes:                SFTypeList;                 {types of files to display}
    myPoint:                Point;                      {upper-left corner of box}
    myNumTypes:             Integer;
    myModalFilter:          ModalFilterYDProcPtr;
    myActiveList:           Ptr;
    myActivateProc:         ActivateYDProcPtr;
    myName:                 Str255;
CONST
    rGetDirectoryDLOG       = 128;                      {resource ID of custom dialog box}
BEGIN
    gPrevSelectedName := '';                    {initialize name of previous selection}
    gDirSelectionFlag := TRUE;                  {initialize directory selection flag}
    myNumTypes := -1;                           {pass all types of files to file filter}
    myPoint.h := -1;                            {center dialog box on screen}
    myPoint.v := -1;
    myModalFilter := NIL;
    myActiveList := NIL;
    myActivateProc := NIL;

    CustomGetFile(@MyCustomFileFilter, myNumTypes, myTypes, myReply,
                        rGetDirectoryDLOG, myPoint, @MyDlgHook, myModalFilter,
                        myActiveList, myActivateProc, @myReply);
    {Get the name of the directory.}
    IF gDirSelectionFlag AND myReply.sfIsVolume THEN
        myName := Concat(myReply.sfFile.name, ':')
    ELSE
        myName := myReply.sfFile.name;

    IF gDirSelectionFlag AND myReply.sfIsVolume THEN
        myReply.sfFile.name := myName
    ELSE IF gDirSelectionFlag THEN
        myReply.sfFile.name := gPrevSelectedName;
    gDirSelectionFlag := FALSE;
    DoGetDirectory := myReply;
END;

The DoGetDirectory function initializes the two global variables gPrevSelectedName and gDirSelectionFlag. As you have seen, these two variables are used by the custom dialog hook function. Then DoGetDirectory calls CustomGetFile to display the directory selection dialog box and handle user selections. When the user selects a directory or clicks the Cancel button, the dialog hook function returns sfItemCancelButton and CustomGetFile exits. At that point, the reply record contains information about the last item selected in the list of available items.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next